package com.jl.utils.niuniu;

import cn.hutool.core.collection.CollectionUtil;
import com.jl.model.Poker;
import com.jl.model.niuniu.enums.SpecialCardType;
import com.jl.model.niuniu.enums.SpecialCardType2;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Auther: zhouhao
 * @Date: 2020/5/7
 * @Description: 获取玩家牌面类型工具类
 */
public class CardUtils {

//    public static void main(String[] args) {
//        PokerResult pokerResult = new PokerResult();
//        PokerResult pokerResult2 = new PokerResult();
//        List<Poker> list = new ArrayList<>();
//        Poker poker = new Poker("1","9");
//        Poker poker2 = new Poker("2","8");
//        Poker poker3 = new Poker("3","6");
//        Poker poker4 = new Poker("3","7");
//        Poker poker5 = new Poker("1","5");
//        list.add(poker);list.add(poker2);list.add(poker3);list.add(poker4);list.add(poker5);
//        List<Poker> list2 = new ArrayList<>();
//        Poker poker111 = new Poker("1","11");
//        Poker poker222 = new Poker("2","8");
//        Poker poker333 = new Poker("2","7");
//        Poker poker444 = new Poker("4","10");
//        Poker poker555 = new Poker("1","6");
//        list2.add(poker111);list2.add(poker222);list2.add(poker333);list2.add(poker444);list2.add(poker555);
//        pokerResult.setPokerList(list);pokerResult.setCardType(CardType.type21);
//        pokerResult2.setPokerList(list2);pokerResult2.setCardType(CardType.type21);
////        int i = compareTo(pokerResult, pokerResult2);
//        PokerResult pokerResult1 = getPokerResult(list, new GlobalData(), 1, "");
//
//        System.out.println(pokerResult1);
//    }

    public static PokerResult getPokerResult(List<Poker> list,GlobalData globalData,int type,String specialCard){
        List<Card> cards = toCardList(list, type);
        CardResult result = getResult(cards, globalData,specialCard);
        List<Poker> pokers = new ArrayList<>();
        for (Card card : result.getCardList()) {
            Poker poker = new Poker();
            poker.setColour(card.getSuitType());
            poker.setValue(card.getFaceType());
            poker.setType(card.getType());
            pokers.add(poker);
        }
        PokerResult pokerResult = new PokerResult();
        pokerResult.setPokerList(pokers);
        pokerResult.setCardType(result.getCardType());
        return pokerResult;
    }

    public static int compareTo(PokerResult o1,PokerResult o2){
        if (o1.getCardType().equals(o2.getCardType())){ //牌类型相同
            return compareToSamePoker(o1.getPokerList(),o2.getPokerList());
        }else {
            return new BigDecimal(o2.getCardType().getId()).compareTo(new BigDecimal(o1.getCardType().getId()));
        }
    }

    public static int compareToSamePoker(List<Poker> o1,List<Poker> o2){
        Poker poker1 = o1.stream().max((a1, a2) -> Integer.valueOf(a1.getValue()).compareTo(Integer.valueOf(a2.getValue()))).get();
        Poker poker2 = o2.stream().max((a1, a2) -> Integer.valueOf(a1.getValue()).compareTo(Integer.valueOf(a2.getValue()))).get();
        int i = new BigDecimal(poker1.getValue()).compareTo(new BigDecimal(poker2.getValue()));
        if (i==0){
            return new BigDecimal(poker2.getColour()).compareTo(new BigDecimal(poker1.getColour()));
        }else {
            return i;
        }
    }

    public static CardResult getResult(List<Card> list,GlobalData globalData,String specialCard){
        List<List<Card>> newListCards = new ArrayList<>();
        List<Card> cards = new ArrayList<>();
        for (Card card : list) {
            if (!card.getSuitType().equals("king")){
                cards.add(card);
            }
        }
        ArrayList<String> newQueue = new ArrayList<>(globalData.getQueue());
        if (cards.size()==3){ //两张王
            for (int i = 0; i < newQueue.size()-1; i++) {
                for (int j = i+1; j < newQueue.size(); j++) {
                    List<Card> cardList = new ArrayList<>(cards);
                    Card card = new Card(newQueue.get(i),splitStr(newQueue.get(i),0),splitStr(newQueue.get(i),1),2);
                    Card card2 = new Card(newQueue.get(j),splitStr(newQueue.get(j),0),splitStr(newQueue.get(j),1),2);
                    cardList.add(card);
                    cardList.add(card2);
                    newListCards.add(cardList);
                }
            }
        }else if(cards.size()==4){ //一张王
            for (int i = 0; i < newQueue.size(); i++) {
                if (newQueue.get(i).contains("king")){ //又抽到一张王
                    continue;
                }
                List<Card> cardList = new ArrayList<>(cards);
                Card card = new Card(newQueue.get(i),splitStr(newQueue.get(i),0),splitStr(newQueue.get(i),1),2);
                cardList.add(card);
                newListCards.add(cardList);
            }
        }
        if (CollectionUtil.isNotEmpty(newListCards)){
            List<CardResult> cardResults = new ArrayList<>();
            for (List<Card> newListCard : newListCards) {
                CardResult cardResult = new CardResult();
                CardType type = CardUtils.getType(newListCard,specialCard);
                cardResult.setCardList(newListCard);
                cardResult.setCardType(type);
                cardResults.add(cardResult);
            }
            CardResult cardResult = cardResults.stream().max(new Comparator<CardResult>() {
                @Override
                public int compare(CardResult o1, CardResult o2) {
                    return Integer.valueOf(o2.getCardType().getId()) - Integer.valueOf(o1.getCardType().getId());
                }
            }).get();
            return cardResult;
        }else { //无癞子
            CardResult cardResult = new CardResult();
            CardType type = getType(list,specialCard);
            cardResult.setCardList(list);
            cardResult.setCardType(type);
            return cardResult;
        }
    }


    public static CardType getType(List<Card> niuNiu,String specialCard){
//        个人牌面总大小
        int sum =0;
        CardType c =null;
        //真实牌面 JQK分别算为 11 12 13
        List<Integer> realface = niuNiu.stream().map(f->Integer.valueOf(f.getFaceType())).sorted().collect(Collectors.toList());
        //JQK算为10的牌面
        List<Integer> faceTen = niuNiu.stream().map(f ->getNum(f.getFaceType())).sorted().collect(Collectors.toList());
        //花色
        List<Integer> flower = niuNiu.stream().map(f->Integer.valueOf(f.getSuitType())).sorted().collect(Collectors.toList());

        sum =getSum(faceTen);
//            判断是否同花
        if(isSraightFlush(flower) && (specialCard.contains(CardType.type1.getId())||specialCard.contains(CardType.type6.getId()))){
//               判断是否连号
            if(specialCard.contains(CardType.type1.getId())&&isConsecutive(realface)){
//                   同花顺
                c=CardType.type1;
            }else if (specialCard.contains(CardType.type6.getId())){
                c=CardType.type6;
            }
        }else {
//               不同花
            //顺子(连号)
            if(isConsecutive(realface) && (specialCard.contains(CardType.type7.getId())||specialCard.contains(CardType.type2.getId()))){
                if(specialCard.contains(CardType.type2.getId())&&isOneLoong(sum)){
                    //一条龙
                    c=CardType.type2;
                }else if (specialCard.contains(CardType.type7.getId())){
                    //顺子牛
                    c =CardType.type7;
                }
            }else
                //不连号
//               判断五小牛
                if(specialCard.contains(CardType.type3.getId())&&isFiveSmall(sum,faceTen)){
                    //五小牛
                    c=CardType.type3;
                }else {
                    //判断其他特殊牌型
                    c =isBombNiu(realface,faceTen,sum,specialCard);
                }
        }
        return c;
    }

    private static int isNiuNiu(List<Integer> faceTen){
        int sumNew =faceTen.stream().reduce(Integer::sum).orElse(0);
        int lave =sumNew%10;
        int count =0;
        f:for(int l =0;l<faceTen.size()-1;l++){
            for(int n =l+1;n<faceTen.size();n++){
                count =faceTen.get(l)+faceTen.get(n);
                if( (count %10==lave)&& ((sumNew-count)%10==0) ){
                    //有牛
                    count= count>=10? count %10 : count;
                    break f;
                }else {
                    count= 100;
                }
            }
        }
        return count;
    }

    /**
     * 获取牌面大小
     * @param s
     * @return
     */
    private static int getNum(String s){
        if(s.equals("11") || s.equals("12") || s.equals("13")){
            return 10;
        }else if(s.equals("1")){
            return 1;
        }else {
            return Integer.valueOf(s);
        }
    }

    /**
     * 是否同花
     * @return
     */
    private static boolean isSraightFlush(List<Integer> flower){
        if(!CollectionUtils.isEmpty(flower) && new HashSet<Integer>(flower).size() ==1){
            return true;
        }
        return false;
    }

    /**
     * 是否一条龙:不同花色的A2345, 调用此方法前提已经是连号了， 方才准确
     * @return
     */
    private static boolean isOneLoong(Integer sum){
        return (sum !=null)&&sum ==15;
    }

    /**
     * 是否连号
     * @return
     */
    private static boolean isConsecutive(List<Integer> realface){
        if(!CollectionUtils.isEmpty(realface)){
            for(int i =0;i<realface.size();i++){
                if(i+1==realface.size()){
                    return true;
                }
                if(!(realface.get(i)+1 == realface.get(i+1))){
                    return false;
                }
            }
            return true;
        }
        return false;
    }

    /**
     * 是否五小牛:不同花色的牌面总和<=10
     * @return
     */
    private static boolean isFiveSmall(Integer sum,List<Integer> faceTen){
        for(int f :faceTen){
            if(f>5){
                return false;
            }
        }
        return (sum !=null)&&sum <=10;
    }

    /**
     * 是否炸弹牛:4张牌面相同
     * @return
     */
    private static CardType isBombNiu(List<Integer> realface,List<Integer> faceTen,int sum,String specialCard){
        Collections.sort(realface);
        int one =realface.get(0);
        int two =realface.get(1);
        int three =realface.get(2);
        int four =realface.get(3);
        int five =realface.get(4);

        // 判断炸弹牛aaaa*  or *aaaa
        if(((one==four) || (two==five))&& specialCard.contains(CardType.type4.getId()) ){
            return CardType.type4;
        }
        //判断葫芦牛 aaabb or aabbb
        if( ((one==three&&four==five) || (one==two&&three==five))&& specialCard.contains(CardType.type5.getId())  ){
            return CardType.type5;
        }
        if(one >10 && specialCard.contains(CardType.type8.getId()) ){
            return CardType.type8;
        }else if(one >=10 && specialCard.contains(CardType.type9.getId()) ){
            return CardType.type9;
        }

        switch (isNiuNiu(faceTen)){
            case 0:
                //比翼牛 aabbc
                // TODO: 2020/4/24 需注意一下  aaabc类型 是否正确
                if(new HashSet<Integer>(realface).size() ==3 && (one == two || two == three) &&
                        (three == four || four == five) && specialCard.contains(CardType.type10.getId())  ){
                    return CardType.type10;
                }
                return CardType.type11;
            case 9:
                return CardType.type12;
            case 8:
                return CardType.type13;
            case 7:
                return CardType.type14;
            case 6:
                return CardType.type15;
            case 5:
                return CardType.type16;
            case 4:
                return CardType.type17;
            case 3:
                return CardType.type18;
            case 2:
                return CardType.type19;
            case 1:
                return CardType.type20;
            default:
                return CardType.type21;
        }
    }

    /**
     * 求牌面总大小
     * @return
     */
    private static int getSum(List<Integer> face){
        return face.stream().reduce(Integer::sum).orElse(0);
    }

    public static String splitStr(String str,int index){
        String[] split = str.split("-");
        return split[index];
    }


    public static List<Card> toCardList(List<Poker> list, int type){
        List<Card> cards = new ArrayList<>();
        for (Poker poker : list) {
            Card card = new Card(null,poker.getColour(),poker.getValue(),type);
            cards.add(card);
        }
        return cards;
    }

    public static int getCardRate(String flopRule,String cardType){
        if (new BigDecimal(cardType).compareTo(new BigDecimal("11"))<0){
            if ("1,2".contains(flopRule)){ //翻倍规则是前两种
                return SpecialCardType.getEnumById(cardType);
            }else {
                return SpecialCardType2.getEnumById(cardType);
            }
        }else {
            switch (flopRule){
                case "1":
                    if (cardType.equals(CardType.type11.getId())){
                        return 3;
                    }else if (cardType.equals(CardType.type12.getId())||cardType.equals(CardType.type13.getId())||cardType.equals(CardType.type14.getId())){
                        return 2;
                    }else {
                        return 1;
                    }
                case "2":
                    if (cardType.equals(CardType.type11.getId())){
                        return 4;
                    }else if (cardType.equals(CardType.type12.getId())){
                        return 3;
                    }else if (cardType.equals(CardType.type13.getId())||cardType.equals(CardType.type14.getId())){
                        return 2;
                    }else {
                        return 1;
                    }
                case "3":
                    if (cardType.equals(CardType.type11.getId())){
                        return 10;
                    }else if (cardType.equals(CardType.type12.getId())){
                        return 9;
                    }else if (cardType.equals(CardType.type13.getId())){
                        return 8;
                    }else if (cardType.equals(CardType.type14.getId())){
                        return 7;
                    }else if (cardType.equals(CardType.type15.getId())){
                        return 6;
                    }else if (cardType.equals(CardType.type16.getId())){
                        return 5;
                    }else if (cardType.equals(CardType.type17.getId())){
                        return 4;
                    }else if (cardType.equals(CardType.type18.getId())){
                        return 3;
                    }else if (cardType.equals(CardType.type19.getId())){
                        return 2;
                    }else if (cardType.equals(CardType.type20.getId())){
                        return 1;
                    }else if (cardType.equals(CardType.type21.getId())){
                        return 1;
                    }
            }
            return 1;
        }
    }
}
